﻿// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

namespace Neto.Extensions;

public static class DictionaryExtensions
{
    /// <summary>
    ///     尝试将键和值添加到字典中：如果不存在，则添加；存在，则不添加也不抛出异常
    /// </summary>
    /// <typeparam name="TKey">键的类型</typeparam>
    /// <typeparam name="TValue">值的类型</typeparam>
    /// <param name="dict">要操作的字典</param>
    /// <param name="key">要添加的键</param>
    /// <param name="value">要添加的值</param>
    /// <returns>操作后的字典</returns>
    public static Dictionary<TKey, TValue> TryAdd<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key,
        TValue value)
    {
        if (dict == null) throw new ArgumentNullException(nameof(dict));
        if (!dict.ContainsKey(key)) dict.Add(key, value);
        return dict;
    }

    /// <summary>
    ///     将键和值添加或替换到字典中：如果不存在，则添加；存在，则替换
    /// </summary>
    /// <typeparam name="TKey">键的类型</typeparam>
    /// <typeparam name="TValue">值的类型</typeparam>
    /// <param name="dict">要操作的字典</param>
    /// <param name="key">要添加或替换的键</param>
    /// <param name="value">要添加或替换的值</param>
    /// <returns>操作后的字典</returns>
    public static Dictionary<TKey, TValue> AddOrUpdate<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key,
        TValue value)
    {
        if (dict == null) throw new ArgumentNullException(nameof(dict));
        dict[key] = value;
        return dict;
    }

    /// <summary>
    ///     判断集合中是否存在指定的键，不区分大小写
    /// </summary>
    /// <typeparam name="TKey">键的类型</typeparam>
    /// <typeparam name="TValue">值的类型</typeparam>
    /// <param name="dictionary">数据字典</param>
    /// <param name="key">关键词</param>
    /// <returns>是否存在指定的键</returns>
    public static bool ContainsKeyIgnoreCase<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
    {
        if (dictionary == null) return false;

        if (key is string keyString)
            return dictionary.Keys.OfType<string>()
                .Any(k => string.Equals(k, keyString, StringComparison.OrdinalIgnoreCase));

        return dictionary.ContainsKey(key);
    }

    /// <summary>
    ///     获取字典的值
    /// </summary>
    /// <typeparam name="TKey">键的类型</typeparam>
    /// <typeparam name="TValue">值的类型</typeparam>
    /// <param name="dict">要操作的字典</param>
    /// <param name="key">要获取的键</param>
    /// <returns>键对应的值，如果键不存在则返回默认值</returns>
    public static TValue GetValue<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key)
    {
        if (dict == null) return default;
        return dict.TryGetValue(key, out var value) ? value : default;
    }

    /// <summary>
    ///     获取字典的值，并转换为指定的对象
    /// </summary>
    /// <typeparam name="T">目标类型</typeparam>
    /// <param name="dict">要操作的字典</param>
    /// <param name="key">要获取的键</param>
    /// <returns>键对应的值，转换为指定的对象类型；如果转换失败则返回默认值</returns>
    public static T GetObject<T>(this Dictionary<string, object>? dict, string key) where T : class, new()
    {
        if (dict == null || !dict.TryGetValue(key, out var value)) return new T();

        try
        {
            return value as T ?? new T();
        }
        catch
        {
            return new T();
        }
    }

    /// <summary>
    ///     获取字典的值，并转换为指定的类型
    /// </summary>
    /// <typeparam name="T">目标类型</typeparam>
    /// <param name="dict">要操作的字典</param>
    /// <param name="key">要获取的键</param>
    /// <returns>键对应的值，转换为指定的类型；如果转换失败则返回默认值</returns>
    public static T? GetValue<T>(this Dictionary<string, object>? dict, string key)
    {
        if (dict == null || !dict.TryGetValue(key, out var value)) return default;

        try
        {
            return value is T result ? result : default;
        }
        catch
        {
            return default;
        }
    }

    /// <summary>
    ///     获取字典的值，并转换为字符串
    /// </summary>
    /// <param name="dict">要操作的字典</param>
    /// <param name="key">要获取的键</param>
    /// <returns>键对应的值，转换为字符串；如果转换失败则返回空字符串</returns>
    public static string GetStringValue(this Dictionary<string, object>? dict, string key)
    {
        if (dict == null || !dict.TryGetValue(key, out var value)) return string.Empty;

        try
        {
            return value is string result ? result : string.Empty;
        }
        catch
        {
            return string.Empty;
        }
    }

    /// <summary>
    ///     将字典的键转换为小写
    /// </summary>
    /// <typeparam name="TValue">值的类型</typeparam>
    /// <param name="obj">要操作的字典</param>
    /// <returns>键为小写的字典</returns>
    public static Dictionary<string, TValue> ToKeyLowerCase<TValue>(this Dictionary<string, TValue> obj)
    {
        if (obj == null) return obj;
        return obj.ToDictionary(kvp => kvp.Key.ToLowerInvariant(), kvp => kvp.Value);
    }

    /// <summary>
    ///     将并发字典的键转换为小写
    /// </summary>
    /// <typeparam name="TValue">值的类型</typeparam>
    /// <param name="obj">要操作的并发字典</param>
    /// <returns>键为小写的并发字典</returns>
    public static ConcurrentDictionary<string, TValue> ToKeyLowerCase<TValue>(
        this ConcurrentDictionary<string, TValue> obj)
    {
        if (obj == null) return obj;
        var newDict = new ConcurrentDictionary<string, TValue>();
        foreach (var kvp in obj) newDict.TryAdd(kvp.Key.ToLowerInvariant(), kvp.Value);
        return newDict;
    }

    /// <summary>
    ///     添加或更新并发字典中的键值对
    /// </summary>
    /// <typeparam name="TKey">键的类型</typeparam>
    /// <typeparam name="TValue">值的类型</typeparam>
    /// <param name="obj">要操作的并发字典</param>
    /// <param name="key">要添加或更新的键</param>
    /// <param name="value">要添加或更新的值</param>
    public static void AbcAddOrUpdate<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> obj, TKey key, TValue value)
        where TKey : notnull
    {
        if (obj == null) throw new ArgumentNullException(nameof(obj));
        obj.AddOrUpdate(key, value, (_, _) => value);
    }

    /// <summary>
    ///     将对象转换为字典
    /// </summary>
    /// <param name="values"></param>
    /// <returns></returns>
    public static Dictionary<string, string> ToDictionary(this object? values)
    {
        var dictionary = new Dictionary<string, string>();
        if (values != null)
            foreach (var property in values.GetType().GetProperties())
            {
                var obj = property.GetValue(values, null) ?? string.Empty;
                dictionary.Add(property.Name, obj.ToString() ?? string.Empty);
            }

        return dictionary;
    }
}